package ExecuteEngine;

import java.util.ArrayList;
import java.util.List;

import parse.*;
import Const.*;
import IndexComponent.*;
import RecordManagement.*;
import SystemManagement.*;

public class Index_select extends Operation{
	public Boolean_factor condition;
	public String tableName;
	public Tuple t;
	public List<String> titles;
	public RM_FileHandle fileHandle;
	String attrName;
	SM_Manager sm;
	List<DataAttrInfo> info;
	int count = 0;
	List<RM_Record> record;
	
	public Index_select(Boolean_factor factor, String tableName, SM_Manager sm){
		this.sm = sm;
		this.condition = factor;
		this.tableName = tableName;
		this.type = Operation.INDEXSELECT;
		this.attrName = factor.attrName;
		this.titles = new ArrayList<String>();
	}
	
	public RC.rc Open(){
		record = new ArrayList<RM_Record>();
		
		try{
			fileHandle = sm.OpenFile(this.tableName);
		}
		catch(Error e){
			throw e;
		}
		
		info = new ArrayList<DataAttrInfo>();
		
		sm.GetDataAttrInfo(this.tableName, this.info);
		
		int type = 0;
		int length = 0;
		
		for(int i=0; i<info.size(); i++){
		    titles.add(Tuple.Trim(info.get(i).attrName));
		    
		    if(Tuple.Trim((info.get(i).attrName)).equals(Tuple.Trim(condition.attrName))){
		    	type = info.get(i).attrType;
		    	length = info.get(i).attrLength;
		    }
		}
		
		IX_Manager ix = sm.ix;
		int indexNo = sm.GetIndexNo(tableName, attrName);
		
		IX_IndexHandle ixHandle = null;
		try{
			ixHandle = sm.ix.OpenIndex(Tuple.Trim(tableName), indexNo);
		}
		catch(java.io.IOException e){
		}
		catch(IX_Abort_Exception e2){
			System.out.println("The index does not exist");
			return RC.rc.IXM_IXNOTFOUND;
		}
		
		IX_IndexScan iscan = null;
		
		if(condition.not == Boolean_factor.NOT){
			switch(condition.op){
				case Expression.EQ:{
					condition.op = Expression.NEQ;
					break;
				}
				case Expression.GE:{
					condition.op = Expression.LT;
					break;
				}
				case Expression.GT:{
					condition.op = Expression.LE;
					break;
				}
				case Expression.LE:{
					condition.op = Expression.GT;
					break;
				}
				case Expression.LT:{
					condition.op = Expression.GE;
					break;
				}
				case Expression.NEQ:{
					condition.op = Expression.EQ;
					break;
				}
			}
		}
		
		if(condition.op != Expression.NEQ){
			if(type == ScanType.TYPE_STRING)
				iscan = ixHandle.OpenScan(condition.op, new StringKeyword(Tuple.Trim(condition.strValue), length));
			else
				iscan = ixHandle.OpenScan(condition.op, new IntKeyword(condition.intValue));
			
			RID rid = null;
			while((rid = iscan.GetNextEntry())!=null){
				record.add(fileHandle.GetRec(rid));
			}
			iscan.CloseScan();
			ix.CloseIndex(ixHandle);
		}
		else{
			if(type == ScanType.TYPE_STRING)
				iscan = ixHandle.OpenScan(IX_IndexScan.OP_GT, new StringKeyword(Tuple.Trim(condition.strValue), length));
			else
				iscan = ixHandle.OpenScan(IX_IndexScan.OP_GT, new IntKeyword(condition.intValue));
			
			RID rid = null;
			while((rid = iscan.GetNextEntry())!=null){
				record.add(fileHandle.GetRec(rid));
			}
			iscan.CloseScan();
			
			if(type == ScanType.TYPE_STRING)
				iscan = ixHandle.OpenScan(IX_IndexScan.OP_LT, new StringKeyword(Tuple.Trim(condition.strValue), length));
			else
				iscan = ixHandle.OpenScan(IX_IndexScan.OP_LT, new IntKeyword(condition.intValue));
			
			rid = null;
			while((rid = iscan.GetNextEntry())!=null){
				record.add(fileHandle.GetRec(rid));
			}
			iscan.CloseScan();
			ix.CloseIndex(ixHandle);
		}
		
		return RC.rc.SUCCESS;
	}
	
	public boolean hasNext(){
		if(count < record.size())
			return true;
		else
			return false;
	}
	
	public Tuple GetNext()
	{	   
		RM_Record r = record.get(count);
		
		t = new Tuple();
		for(int i=0; i<info.size(); i++)
			t.tuple.add(new Element(tableName, info.get(i).attrName, null));
		
		int position = 0;
		for(int i=0; i<info.size(); i++){
			int length = info.get(i).attrLength;
			
			byte b[] = new byte[length];
			System.arraycopy(r.data, position, b, 0, length);
			
			if(info.get(i).attrType == ScanType.TYPE_STRING)
				t.tuple.get(i).setValue(new VarcharItem(new StringBuffer(new String(b))));
			else
				t.tuple.get(i).setValue(new IntegerItem(Tuple.BytesToInt(b)));
			
			position += length;
		}
		count++;
		
		return t;
	}
	
	public void Close(){
		sm.CloseFile(fileHandle);
	}
	
	public List<String> GetTitles(){
		return titles;
	}
}
